class Tone {
  constructor (relativeTone, level = 0,  base = 0) {
    this.value = relativeTone + base + level * 12
  }
  _getRelativeToneAndLevelByBase (base) {
    const level = Math.floor((this.value - base) / 12) 
    const relativeTone = this.value - base - level * 12
    return { level, relativeTone }
  }
  _isGood (base = 0) {
    return [0, 2, 4, 5, 7, 9, 11].includes(this._getRelativeToneAndLevelByBase(base).relativeTone)
  }
  getDetail (base = 0) {
    const letterList = [ 'C', '#C', 'D', '#D', 'E', 'F', '#F', 'G', '#G', 'A', '#A', 'B' ]
    const numberList = [ '1', '#1', '2', '#2', '3', '4', '#4', '5', '#5', '6', '#6', '7' ]
    const { level, relativeTone } = this._getRelativeToneAndLevelByBase(base)
    return {
      letter: letterList[relativeTone],
      number: numberList[relativeTone],
      isGood: this._isGood(base),
      level,
      relativeTone
    }
  }
  equals (tone) {
    return this.value === tone.value
  }
}

class Hole {
  constructor (type, level) { // For 12 hole mouse organ: type: [0, 1, 2, 3] level: -1, 0, 1
    const getRelativeTonesByType = type => [[2, 0, 3, 1], [5, 4, 6, 5], [9, 7, 10, 8], [11, 12, 12, 13]][type]
    this.type = type
    this.level = level
    this.sort = type + level * 4 + 5
    this.actions = getRelativeTonesByType(type).map((relativeTone, actionIndex) => {
      return {
        hole: this,
        tone: new Tone(relativeTone, level),
        isPress: actionIndex > 1,
        isExhale: [0, 2].includes(actionIndex),
        isInhale: [1, 3].includes(actionIndex)
      }
    })
  }
  findActionByTone (tone) {
    return this.actions.findIndex(i => i.tone.value === tone.value)
  }
}

export default class MouseOrgan {
  constructor (size = 12) {
    const holes16 = [];
    [-2, -1, 0, 1].forEach(level => {
      [0, 1, 2, 3].forEach(type => {
        holes16.push(new Hole(type, level))
      })
    })
    this.holes = holes16.reverse().slice(0, size).reverse()
    this.holes.forEach((i, index) => i.sort = index)
  }
  findAllSameTone (tone) {
    const result = []
    this.holes.forEach((hole, holeIndex) => {
      hole.actions.forEach((action, actionIndex) => {
        if (action.tone.equals(tone)) {
          result.push({
            holeIndex, actionIndex, action, tone: action.tone
          })
        }
      })
    })
  }
  // To do: 根据上下文切换难度，自动推荐 action, 因涉及时间， 需配合音频处理导入后才可有用武之地，待完善
  //        目前发现上文的初始值需要想个办法定下来，可能就用音稍微高些的那个
  //        下文的处理有些麻烦，因为下文的后面 action 还需要当前这个来定，待思考
  findRecommendedAction (tone, lastTone, nextTone) {
    const actionList = this.findAllSameTone(tone)
    // actionList.sort((a, b) => {
    //   const difficultyA = this._countDifficultyBetweenTwoAction(lastTone, a) + (this._countDifficultyBetweenTwoAction(a, nextTone))
    // })
  }
  _countDifficultyBetweenTwoAction (startAction, endAction) {
    const moveDifficulty = Math.abs(startAction.hole.sort - endAction.hole.sort) * 100
    const pressDifficulty = startAction.isPress === endAction.isPress ? 0 : 100
    const changeBreathDifficulty = startAction.isInhale === endAction.isInhale ? 0 : 50
    return moveDifficulty + pressDifficulty + changeBreathDifficulty
  }
}

class Tune {
  constructor (content, base = 0) {
    this.content = content 
    this.base = base
  }
}